import datetime
import os
import re
import shutil
import stat
import sys
import time

import paramiko

import LinuxContains

install_fail_dict = {}
install_success_dict = {}
total_hap_num = 0
hap_install_success = 0
hap_install_fail = 0
special_num = 0
special_hap_list = []
def exec_cmd(cmd):
    f = os.popen("hdc shell " + "\"" + cmd + "\"")
    print(cmd)
    text = f.read()
    f.close()
    return text


def exec_cmd_path(cmd, path):
    f = os.popen("hdc shell " + "\"" + cmd + "\" >> " + path)
    print(cmd)
    text = f.read()
    f.close()
    return text


def exec_cmd_simple(cmd):
    f = os.popen(cmd)
    print(cmd)
    text = f.read()
    f.close()
    return text


def sftp_download(sftp, local_dir, remote_dir):
    if stat.S_ISDIR(sftp.stat(remote_dir).st_mode):  # 如果sftp服务端的remoterDir是目录，则返回True
        for file in sftp.listdir(remote_dir):
            remote_dir_tmp = os.path.join(remote_dir, file)
            local_dir_tmp = os.path.join(local_dir, file)
            sftp_download(sftp, local_dir_tmp, remote_dir_tmp)
    else:
        print("download file:", remote_dir)
        try:
            sftp.get(remote_dir, local_dir)
        except Exception as e:
            print('download exception:', e)


def sftp_from_remote(local_path, log_path, success_log_path):
    host = LinuxContains.HOST  # sftp主机
    port = LinuxContains.PORT  # 端口
    username = LinuxContains.USERNAME  # sftp用户名
    password = LinuxContains.PASSWD
    local_dir = local_path
    local_log_path = log_path

    remote_dir_pub = LinuxContains.SIGN_HAP_DIR  # 远程文件或目录
    remote_dir_ful = LinuxContains.FULL_SIGN_HAP_DIR  # 远程文件或目录

    remote_log = LinuxContains.ERROR_LOG_PATH
    remote_log_full = LinuxContains.FULL_ERROR_LOG_PATH

    remote_success_log = LinuxContains.ERROR_LOG_PATH
    remote_success_log_full = LinuxContains.FULL_ERROR_LOG_PATH

    print("download start")
    sf = paramiko.Transport((host, port))
    sf.connect(username=username, password=password)
    sftp = paramiko.SFTPClient.from_transport(sf)
    sftp_download(sftp, local_dir, remote_dir_pub)
    sftp_download(sftp, local_dir, remote_dir_ful)
    sftp_download(sftp, local_log_path, remote_log)
    sftp_download(sftp, local_log_path, remote_log_full)
    sftp_download(sftp, success_log_path, remote_success_log)
    sftp_download(sftp, success_log_path, remote_success_log_full)
    sf.close()
    print("download stop\n")


def get_haps(local_dir):
    files = os.listdir(local_dir)
    hap_list = []
    for file in files:
        if "_signed" in file:
            hap_list.append(file)
    return hap_list


def install_hap(local_hap, hap_path, base_dir):
    for hap in local_hap:
        print("install " + hap_path + "\\" + hap)
        install_res = exec_cmd_simple("hdc install -r {}".format(hap_path + "\\" + hap))
        print(install_res)
        if not install_res.__contains__("msg:install bundle successfully."):
            install_res = install_res.replace("\nAppMod finish\n\n", "")
            install_fail_dict[hap] = install_res
        else:
            exec_cmd_simple("echo install {0} success! >> {1}".format(hap, "{0}\\auto_test.log".format(base_dir)))
            install_success_dict[hap] = install_res
    time.sleep(3)


def start_log():
    cmd_clean = "rm -r /data/log/hilog/*"
    cmd_start = "hilog -w start -l 1M"
    exec_cmd(cmd_clean)
    print(exec_cmd(cmd_start))


def stop_log():
    cmd_stop = "hilog -w stop"
    print(exec_cmd(cmd_stop))


def recv_log(local_log):
    file_path = local_log
    cmd = "hdc file recv /data/log/hilog/ {}".format(file_path)
    print(exec_cmd_simple(cmd))


def test_and_uninstall_hap(begin_bundles, base_dir):
    end_bundles = get_all_bundles()
    uninstall_bundles = list(set(end_bundles) - set(begin_bundles))
    cmd = r"aa test -b {} -p com.example.entry_test -m entry_test -s unittest OpenHarmonyTestRunner -s timeout 30000000"
    path = "{0}\\auto_test.log".format(base_dir)
    for bundle in uninstall_bundles:
        bundle = bundle.strip()
        exec_cmd_simple("echo ================start {0} ui test================{1} >> {2}".format(bundle,
                                                                                                  datetime.datetime.now().strftime(
                                                                                                      '%Y-%m-%d %H:%M:%S'),
                                                                                                  path))
        print("test " + bundle)
        tmp_cmd = cmd.format(bundle)
        exec_cmd_path(tmp_cmd, path)
        print("uninstall " + bundle)
        uninstall_res = exec_cmd_simple("hdc uninstall {}".format(bundle))
        time.sleep(5)


def clear_dir(dir_path):
    if os.path.exists(dir_path):
        shutil.rmtree(dir_path)
    os.makedirs(dir_path)


def clear_file(file_path):
    if os.path.exists(file_path):
        os.remove(file_path)
    os.system(r"type nul>{}".format(file_path))


def get_all_bundles():
    bundles = exec_cmd("bm dump -a")
    bundles = bundles.splitlines()
    del bundles[0]
    return bundles


def batch_install(haps, base_dir):
    start_log()
    exec_cmd_simple("hdc shell power-shell setmode 602")
    # exec_cmd_simple("hdc shell setenforce 0")
    exec_cmd_simple("hdc shell param set persist.ace.testmode.enabled 1")
    limit = 2
    count = 0
    cur_batch_hap = []
    special_haps = LinuxContains.SPECIAL_HAP.split(";")
    begin_bundles = get_all_bundles()
    for hap in haps:
        isSpecial = False
        for special_hap in special_haps:
            if special_hap in hap:
                global special_num
                isSpecial = True
                special_hap_list.append(hap)
                special_num = special_num + 1
                break
        if isSpecial:
            continue

        cur_batch_hap.append(hap)
        count = count + 1
        if count == limit:
            install_hap(cur_batch_hap, "{0}\\SampleSignHap".format(base_dir), base_dir)
            test_and_uninstall_hap(begin_bundles, base_dir)
            count = 0
            cur_batch_hap.clear()
    if len(cur_batch_hap) != 0:
        install_hap(cur_batch_hap, "{0}\\SampleSignHap".format(base_dir), base_dir)
        test_and_uninstall_hap(begin_bundles, base_dir)
        cur_batch_hap.clear()
    stop_log()
    recv_log(base_dir + "\\")


def handle_test_log(base_dir):
    file = open("{0}\\auto_test.log".format(base_dir), encoding='utf-8', errors='ignore')
    p_num = 0
    fail_num = 0
    success_num = 0
    test_exp_num = 0
    test_pass_num = 0
    test_fail_num = 0
    test_error_num = 0
    died_num = 0
    fail_dict = []
    died_dict = []
    curr_name = ""
    has_result = 1
    for x in file:
        if x.startswith(r"================start"):
            if (has_result == 0):
                fail_num = fail_num + 1
                fail_dict.append(curr_name)
            else:
                has_result = 0
            p_num = p_num + 1
            curr_name = x.split(" ")[1]
        if x.startswith(r"OHOS_REPORT_RESULT"):
            has_result = 1
            nums = re.findall(r"\d+", x)
            if len(nums) == 4 or len(nums) == 5:
                if nums[0] == nums[3] and int(nums[0]) != 0:
                    success_num = success_num + 1
                else:
                    fail_num = fail_num + 1
                    fail_dict.append(curr_name)
                test_exp_num = test_exp_num + int(nums[0])
                test_fail_num = test_fail_num + int(nums[1])
                test_error_num = test_error_num + int(nums[2])
                test_pass_num = test_pass_num + int(nums[3])
            else: 
                fail_num = fail_num + 1
                fail_dict.append(curr_name)
        elif x.__contains__("App died"):
            has_result = 1
            died_num = died_num + 1
            died_dict.append(curr_name)
        
    file.close()

    error_log = open("{0}\\auto_test.log".format(base_dir), mode='a')
    error_log.writelines(
        "共完成测试项目 {0}个,成功{1}个，失败{2}个，异常中止(App died){3}个，特殊应用跳过{4}个\n".format(int(p_num + special_num/2), success_num, fail_num, died_num, int(special_num/2 )))
    error_log.writelines(
        "共完成测试用例 {0}个,成功{1}个，失败{2}个，错误{3}个\n".format(test_exp_num, test_pass_num, test_fail_num, test_error_num))
    if len(fail_dict) > 0:
        error_log.writelines("失败工程BundleName如下：\n")
        for x in fail_dict:
            error_log.writelines("     " + x + "\n")
    if len(died_dict) > 0:
        error_log.writelines("异常中止(App died)工程BundleName如下：\n")
        for x in died_dict:
            error_log.writelines("     " + x + "\n")
    error_log.writelines("安装失败项目数量:{0}\n".format(len(install_fail_dict)))
    for i in install_fail_dict:
        error_log.writelines('{0} : {1}'.format(i, install_fail_dict[i]))
    if len(special_hap_list) > 0:
        error_log.writelines("特殊安装跳过Hap数量:{0}\n".format(special_num)) 
        for i in special_hap_list:
            error_log.writelines(i + "\n")
    error_log.flush()
    error_log.close()


def init_out():
    base_dir = sys.path[0]
    out_path = "{0}\\ui_test_out\\{1}".format(base_dir, datetime.datetime.now().strftime('%Y%m%d'))
    clear_dir(out_path)
    clear_dir("{0}\\errorLog".format(out_path))
    clear_dir("{0}\\successLog".format(out_path))
    clear_dir("{0}\\SampleSignHap".format(out_path))
    clear_file("{0}\\auto_test.log".format(out_path))
    clear_dir("{0}\\hilog".format(out_path))
    return out_path


if __name__ == '__main__':
    out_base = init_out()
    sftp_from_remote("{0}\\SampleSignHap".format(out_base), "{0}\\errorLog".format(out_base), "{0}\\successLog".format(out_base))
    haps = get_haps("{0}\\SampleSignHap".format(out_base))
    total_hap_num = len(haps) / 2
    batch_install(haps, out_base)
    handle_test_log(out_base)
